home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 176-200 / 190 / nethack / twee.zoo / shk.c < prev    next >
C/C++ Source or Header  |  1988-07-24  |  28KB  |  1,117 lines

  1. /*    SCCS Id: @(#)shk.c      2.3     88/01/24
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  
  4. #include "hack.h"
  5. #ifdef QUEST
  6. int shlevel = 0;
  7. struct monst *mkmon_at(), *shopkeeper = 0;
  8. struct    obj    *billobjs = 0;
  9. obfree(obj,merge) register struct obj *obj, *merge; {
  10.     free((char *) obj);
  11. }
  12. inshop(){ return(0); }
  13. addtobill(){}
  14. subfrombill(){}
  15. splitbill(){}
  16. dopay(){ return(0); }
  17. paybill(){}
  18. doinvbill(){ return(0); }
  19. shkdead(){}
  20. shkcatch(){ return(0); }
  21. shk_move(){ return(0); }
  22. replshk(mtmp,mtmp2) struct monst *mtmp, *mtmp2; {}
  23. char *shkname(){ return(""); }
  24.  
  25. #else
  26. #include    "mfndpos.h"
  27. #include    "mkroom.h"
  28. #include    "eshk.h"
  29.  
  30. #define ESHK(mon)       ((struct eshk *)(&(mon->mextra[0])))
  31. #define NOTANGRY(mon)   mon->mpeaceful
  32. #define ANGRY(mon)      !NOTANGRY(mon)
  33.  
  34. extern char plname[], *xname();
  35. extern struct monst *makemon();
  36. extern struct obj *o_on(), *bp_to_obj(),
  37.           *carrying();
  38.  
  39. /* Descriptor of current shopkeeper. Note that the bill need not be
  40.    per-shopkeeper, since it is valid only when in a shop. */
  41. static struct monst *shopkeeper = 0;
  42. static struct bill_x *bill;
  43. static int shlevel = 0; /* level of this shopkeeper */
  44.        struct obj *billobjs;    /* objects on bill with bp->useup */
  45.                 /* only accessed here and by save & restore */
  46. static long int total;        /* filled by addupbill() */
  47. static long int followmsg;    /* last time of follow message */
  48. static setpaid(), findshk(), dopayobj(), getprice(), realhunger();
  49.  
  50. /*
  51.     invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
  52.         obj->quan <= bp->bquan
  53.  */
  54.  
  55. char *
  56. shkname(mtmp)                           /* called in do_name.c */
  57. register struct monst *mtmp;
  58. {
  59.     return(ESHK(mtmp)->shknam);
  60. }
  61.  
  62. shkdead(mtmp)                           /* called in mon.c */
  63. register struct monst *mtmp;
  64. {
  65.     register struct eshk *eshk = ESHK(mtmp);
  66.  
  67.     if(eshk->shoplevel == dlevel)
  68.         rooms[eshk->shoproom].rtype = OROOM;
  69.     if(mtmp == shopkeeper) {
  70.         setpaid();
  71.         shopkeeper = 0;
  72.         bill = (struct bill_x *) -1000; /* dump core when referenced */
  73.     }
  74. }
  75.  
  76. replshk(mtmp,mtmp2)
  77. register struct monst *mtmp, *mtmp2;
  78. {
  79.     if(mtmp == shopkeeper) {
  80.         shopkeeper = mtmp2;
  81.         bill = &(ESHK(shopkeeper)->bill[0]);
  82.     }
  83. }
  84.  
  85. static
  86. setpaid(){      /* caller has checked that shopkeeper exists */
  87.         /* either we paid or left the shop or he just died */
  88. register struct obj *obj;
  89. register struct monst *mtmp;
  90.     for(obj = invent; obj; obj = obj->nobj)
  91.         obj->unpaid = 0;
  92.     for(obj = fobj; obj; obj = obj->nobj)
  93.         obj->unpaid = 0;
  94.     for(obj = fcobj; obj; obj = obj->nobj)
  95.         obj->unpaid = 0;
  96.     for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
  97.         for(obj = mtmp->minvent; obj; obj = obj->nobj)
  98.             obj->unpaid = 0;
  99.     for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon)
  100.         for(obj = mtmp->minvent; obj; obj = obj->nobj)
  101.             obj->unpaid = 0;
  102.     while(obj = billobjs){
  103.         billobjs = obj->nobj;
  104.         free((char *) obj);
  105.     }
  106.     ESHK(shopkeeper)->billct = 0;
  107. }
  108.  
  109. static
  110. addupbill(){    /* delivers result in total */
  111.         /* caller has checked that shopkeeper exists */
  112. register ct = ESHK(shopkeeper)->billct;
  113. register struct bill_x *bp = bill;
  114.     total = 0;
  115.     while(ct--){
  116.         total += bp->price * bp->bquan;
  117.         bp++;
  118.     }
  119. }
  120.  
  121. inshop(){
  122. register roomno = inroom(u.ux,u.uy);
  123.  
  124.     /* Did we just leave a shop? */
  125.     if(u.uinshop &&
  126.         (u.uinshop != roomno + 1 || shlevel != dlevel || !shopkeeper)) {
  127.  
  128.     /* This is part of the bugfix for shopkeepers not having their
  129.      * bill paid.  As reported by ab@unido -dgk
  130.      * I made this standard due to the KOPS code below. -mrs
  131.      */
  132.         if(shopkeeper) {
  133.             if(ESHK(shopkeeper)->billct) {
  134.             if(inroom(shopkeeper->mx, shopkeeper->my)
  135.                 == u.uinshop - 1)    /* ab@unido */
  136.                 pline("Somehow you escaped the shop without paying!");
  137.             addupbill();
  138.             pline("You stole for a total worth of %ld zorkmids.",
  139.                 total);
  140.             ESHK(shopkeeper)->robbed += total;
  141.             setpaid();
  142.             if((rooms[ESHK(shopkeeper)->shoproom].rtype == SHOPBASE)
  143.                 == (rn2(3) == 0))
  144.                 ESHK(shopkeeper)->following = 1;
  145. #ifdef KOPS
  146.             {   /* Keystone Kops srt@ucla */
  147.                 coord mm;
  148.                 register int cnt = dlevel + rnd(3);
  149.                 /* Create a swarm near the staircase */
  150.                 pline("An alarm sounds throughout the dungeon!");
  151.                 pline("The Keystone Kops are after you!");
  152.                 mm.x = xdnstair;
  153.                 mm.y = ydnstair;
  154.                 while(cnt--) {
  155.                     (void) enexto(&mm, mm.x, mm.y);
  156.                     (void) mkmon_at('K', mm.x, mm.y);
  157.                 }
  158.                 /* Create a swarm near the shopkeeper */
  159.                 cnt = dlevel + rnd(3);
  160.                 mm.x = shopkeeper->mx;
  161.                 mm.y = shopkeeper->my;
  162.                 while(cnt--) {
  163.                     (void) enexto(&mm, mm.x, mm.y);
  164.                     (void) mkmon_at('K', mm.x, mm.y);
  165.                 }
  166.             }
  167. #endif
  168.             }
  169.             shopkeeper = 0;
  170.             shlevel = 0;
  171.         }
  172.         u.uinshop = 0;
  173.     }
  174.  
  175.     /* Did we just enter a zoo of some kind? */
  176.     if(roomno >= 0) {
  177.         register int rt = rooms[roomno].rtype;
  178.         register struct monst *mtmp;
  179.         if(rt == ZOO) {
  180.             pline("Welcome to David's treasure zoo!");
  181.         } else
  182.         if(rt == SWAMP) {
  183.             pline("It looks rather muddy down here.");
  184.         } else
  185.         if(rt == COURT) {
  186.             pline("You are in an opulent throne room!");
  187.         } else
  188.         if(rt == MORGUE) {
  189.             if(midnight())
  190.                 pline("Go away! Go away!");
  191.             else
  192.                 pline("You get an uncanny feeling ...");
  193.         } else
  194.             rt = 0;
  195.         if(rt != 0) {
  196.             rooms[roomno].rtype = OROOM;
  197.             for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
  198.                 if(rt != ZOO || !rn2(3))
  199.                     mtmp->msleep = 0;
  200.         }
  201.     }
  202.  
  203.     /* Did we just enter a shop? */
  204.     if(roomno >= 0 && rooms[roomno].rtype >= SHOPBASE) {
  205.         register int rt = rooms[roomno].rtype;
  206.  
  207.         if(shlevel != dlevel || !shopkeeper
  208.                  || ESHK(shopkeeper)->shoproom != roomno)
  209.         findshk(roomno);
  210.         if(!shopkeeper) {
  211.         rooms[roomno].rtype = OROOM;
  212.         u.uinshop = 0;
  213.         } else if(!u.uinshop){
  214.         if(!ESHK(shopkeeper)->visitct ||
  215.             strncmp(ESHK(shopkeeper)->customer, plname, PL_NSIZ)){
  216.  
  217.             /* He seems to be new here */
  218.             ESHK(shopkeeper)->visitct = 0;
  219.             ESHK(shopkeeper)->following = 0;
  220.             (void) strncpy(ESHK(shopkeeper)->customer,plname,PL_NSIZ);
  221.             NOTANGRY(shopkeeper) = 1;
  222.         }
  223.         if(!ESHK(shopkeeper)->following) {
  224.             boolean box, pick;
  225.  
  226.             pline("Hello %s%s! Welcome%s to %s's %s!",
  227.             (Badged) ? "Officer " : "", plname,
  228.             ESHK(shopkeeper)->visitct++ ? " again" : "",
  229.             shkname(shopkeeper),
  230.             shtypes[rt - SHOPBASE].name);
  231. /*            shtypes[rooms[ESHK(shopkeeper)->shoproom].rtype - SHOPBASE].name);
  232. */
  233.             box = carrying(ICE_BOX) != (struct obj *)0;
  234.             pick = carrying(PICK_AXE) != (struct obj *)0;
  235.             if(box || pick) {
  236.             if(dochug(shopkeeper)) {
  237.                 u.uinshop = 0;    /* he died moving */
  238.                 return(0);
  239.             }
  240.             pline("Will you please leave your %s outside?",
  241.                 (box && pick) ? "box and pick-axe" :
  242.                 box ? "box" : "pick-axe");
  243.             }
  244.         }
  245.         u.uinshop = roomno + 1;
  246.         }
  247.     }
  248.     return(u.uinshop);
  249. }
  250.  
  251. static
  252. findshk(roomno)
  253. register roomno;
  254. {
  255. register struct monst *mtmp;
  256.     for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
  257.         if(mtmp->isshk && ESHK(mtmp)->shoproom == roomno
  258.                && ESHK(mtmp)->shoplevel == dlevel) {
  259.         shopkeeper = mtmp;
  260.         bill = &(ESHK(shopkeeper)->bill[0]);
  261.         shlevel = dlevel;
  262.         if(ANGRY(shopkeeper) &&
  263.            strncmp(ESHK(shopkeeper)->customer,plname,PL_NSIZ))
  264.             NOTANGRY(shopkeeper) = 1;
  265.         /* billobjs = 0; -- this is wrong if we save in a shop */
  266.         /* (and it is harmless to have too many things in billobjs) */
  267.         return;
  268.     }
  269.     shopkeeper = 0;
  270.     shlevel = 0;
  271.     bill = (struct bill_x *) -1000; /* dump core when referenced */
  272. }
  273.  
  274. static struct bill_x *
  275. onbill(obj) register struct obj *obj; {
  276. register struct bill_x *bp;
  277.     if(!shopkeeper) return(0);
  278.     for(bp = bill; bp < &bill[ESHK(shopkeeper)->billct]; bp++)
  279.         if(bp->bo_id == obj->o_id) {
  280.             if(!obj->unpaid) pline("onbill: paid obj on bill?");
  281.             return(bp);
  282.         }
  283.     if(obj->unpaid) pline("onbill: unpaid obj not on bill?");
  284.     return(0);
  285. }
  286.  
  287. /* called with two args on merge */
  288. obfree(obj,merge) register struct obj *obj, *merge; {
  289. register struct bill_x *bp = onbill(obj);
  290. register struct bill_x *bpm;
  291.     if(bp) {
  292.         if(!merge){
  293.             bp->useup = 1;
  294.             obj->unpaid = 0;    /* only for doinvbill */
  295.             obj->nobj = billobjs;
  296.             billobjs = obj;
  297.             return;
  298.         }
  299.         bpm = onbill(merge);
  300.         if(!bpm){
  301.             /* this used to be a rename */
  302.             impossible("obfree: not on bill??");
  303.             return;
  304.         } else {
  305.             /* this was a merger */
  306.             bpm->bquan += bp->bquan;
  307.             ESHK(shopkeeper)->billct--;
  308.             *bp = bill[ESHK(shopkeeper)->billct];
  309.         }
  310.     }
  311.     free((char *) obj);
  312. }
  313.  
  314. static
  315. pay(tmp,shkp)
  316. long tmp;
  317. register struct monst *shkp;
  318. {
  319.     long robbed = ESHK(shkp)->robbed;
  320.  
  321.     u.ugold -= tmp;
  322.     shkp->mgold += tmp;
  323.     flags.botl = 1;
  324.     if(robbed) {
  325.         robbed -= tmp;
  326.         if(robbed < 0) robbed = 0;
  327.         ESHK(shkp)->robbed = robbed;
  328.     }
  329. }
  330.  
  331. dopay(){
  332. long ltmp;
  333. register struct bill_x *bp;
  334. register struct monst *shkp;
  335. int pass, tmp;
  336.  
  337.     multi = 0;
  338.     (void) inshop();
  339.     for(shkp = fmon; shkp; shkp = shkp->nmon)
  340.         if(shkp->isshk && dist(shkp->mx,shkp->my) < 3)
  341.             break;
  342.     if(!shkp && u.uinshop &&
  343.        inroom(shopkeeper->mx,shopkeeper->my) == ESHK(shopkeeper)->shoproom)
  344.         shkp = shopkeeper;
  345.  
  346.     if(!shkp) {
  347.         pline("There is nobody here to receive your payment.");
  348.         return(0);
  349.     }
  350.     ltmp = ESHK(shkp)->robbed;
  351.     if(shkp != shopkeeper && NOTANGRY(shkp)) {
  352.         if(!ltmp) {
  353.             pline("You do not owe %s anything.", monnam(shkp));
  354.         } else
  355.         if(!u.ugold) {
  356.             pline("You have no money.");
  357.         } else {
  358.             long ugold = u.ugold;
  359.  
  360.             if(u.ugold > ltmp) {
  361.             pline("You give %s the %ld gold pieces %s asked for.",
  362.             monnam(shkp), ltmp, index("@CGHKLOQTVWZ&ehimt", shkp->data->mlet)
  363.             ? "he" : (index("nN", shkp->data->mlet) ? "she" : "it"));
  364.             pay(ltmp, shkp);
  365.             } else {
  366.             pline("You give %s all your gold.", monnam(shkp));
  367.             pay(u.ugold, shkp);
  368.             }
  369.             if(ugold < ltmp/2) {
  370.             pline("Unfortunately, %s doesn't look satisfied.",
  371.             index("@CGHKLOQTVWZ&ehimt", shkp->data->mlet)
  372.             ? "he" : (index("nN", shkp->data->mlet) ? "she" : "it"));
  373.             } else {
  374.             ESHK(shkp)->robbed = 0;
  375.             ESHK(shkp)->following = 0;
  376.             if(ESHK(shkp)->shoplevel != dlevel) {
  377.             /* For convenience's sake, let him disappear */
  378.                 shkp->minvent = 0;        /* %% */
  379.                 shkp->mgold = 0;
  380.                 mondead(shkp);
  381.             }
  382.             }
  383.         }
  384.         return(1);
  385.     }
  386.  
  387.     if(!ESHK(shkp)->billct){
  388.         pline("You do not owe %s anything.", monnam(shkp));
  389.         if(!u.ugold){
  390.             pline("Moreover, you have no money.");
  391.             return(1);
  392.         }
  393.         if(ESHK(shkp)->robbed){
  394.             pline("But since %s shop has been robbed recently,",
  395.             index("@CGHKLOQTVWZ&ehimt", shkp->data->mlet)
  396.             ? "his" : (index("nN", shkp->data->mlet) ? "her" : "its"));
  397.             pline("you %srepay %s's expenses.",
  398.               (u.ugold < ESHK(shkp)->robbed) ? "partially " : "",
  399.               monnam(shkp));
  400.             pay(min(u.ugold, ESHK(shkp)->robbed), shkp);
  401.             ESHK(shkp)->robbed = 0;
  402.             return(1);
  403.         }
  404.         if(ANGRY(shkp)){
  405.             pline("But in order to appease %s,",
  406.                 amonnam(shkp, "angry"));
  407.             if(u.ugold >= 1000){
  408.                 ltmp = 1000;
  409.                 pline(" you give %s 1000 gold pieces.",
  410.                 index("@CGHKLOQTVWZ&ehimt", shkp->data->mlet)
  411.                 ? "him" : (index("nN", shkp->data->mlet) ? "her" : "it"));
  412.             } else {
  413.                 ltmp = u.ugold;
  414.                 pline(" you give %s all your money.",
  415.                 index("@CGHKLOQTVWZ&ehimt", shkp->data->mlet)
  416.                 ? "him" : (index("nN", shkp->data->mlet) ? "her" : "it"));
  417.             }
  418.             pay(ltmp, shkp);
  419.             if(strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)
  420.                || rn2(3)){
  421.                 pline("%s calms down.", Monnam(shkp));
  422.                 NOTANGRY(shkp) = 1;
  423.             } else    pline("%s is as angry as ever.",
  424.                     Monnam(shkp));
  425.         }
  426.         return(1);
  427.     }
  428.     if(shkp != shopkeeper) {
  429.         impossible("dopay: not to shopkeeper?");
  430.         if(shopkeeper) setpaid();
  431.         return(0);
  432.     }
  433.     for(pass = 0; pass <= 1; pass++) {
  434.         tmp = 0;
  435.         while(tmp < ESHK(shopkeeper)->billct) {
  436.             bp = &bill[tmp];
  437.             if(!pass && !bp->useup) {
  438.                 tmp++;
  439.                 continue;
  440.             }
  441.             if(!dopayobj(bp)) return(1);
  442. #ifdef MSDOS
  443.             *bp = bill[--ESHK(shopkeeper)->billct];
  444. #else
  445.             bill[tmp] = bill[--ESHK(shopkeeper)->billct];
  446. #endif /* MSDOS /**/
  447.         }
  448.     }
  449.     pline("Thank you for shopping in %s's %s!",
  450.         shkname(shopkeeper),
  451.         shtypes[rooms[ESHK(shopkeeper)->shoproom].rtype - SHOPBASE].name);
  452.     NOTANGRY(shopkeeper) = 1;
  453.     return(1);
  454. }
  455.  
  456. /* return 1 if paid successfully */
  457. /*      0 if not enough money */
  458. /*     -1 if object could not be found (but was paid) */
  459. static
  460. dopayobj(bp) register struct bill_x *bp; {
  461. register struct obj *obj;
  462. long ltmp;
  463.  
  464.     /* find the object on one of the lists */
  465.     obj = bp_to_obj(bp);
  466.  
  467.     if(!obj) {
  468.         impossible("Shopkeeper administration out of order.");
  469.         setpaid();      /* be nice to the player */
  470.         return(0);
  471.     }
  472.  
  473.     if(!obj->unpaid && !bp->useup){
  474.         impossible("Paid object on bill??");
  475.         return(1);
  476.     }
  477.     obj->unpaid = 0;
  478.     ltmp = bp->price * bp->bquan;
  479.     if(ANGRY(shopkeeper)) ltmp += ltmp/3;
  480.     if(u.ugold < ltmp){
  481.         pline("You don't have gold enough to pay %s.",
  482.             doname(obj));
  483.         obj->unpaid = 1;
  484.         return(0);
  485.     }
  486.     pay(ltmp, shopkeeper);
  487.     pline("You bought %s for %ld gold piece%s.",
  488.         doname(obj), ltmp, plur(ltmp));
  489.     if(bp->useup) {
  490.         register struct obj *otmp = billobjs;
  491.         if(obj == billobjs)
  492.             billobjs = obj->nobj;
  493.         else {
  494.             while(otmp && otmp->nobj != obj) otmp = otmp->nobj;
  495.             if(otmp) otmp->nobj = obj->nobj;
  496.             else pline("Error in shopkeeper administration.");
  497.         }
  498.         free((char *) obj);
  499.     }
  500.     return(1);
  501. }
  502.  
  503. /* routine called after dying (or quitting) with nonempty bill */
  504. paybill(){
  505.     if(shlevel == dlevel && shopkeeper && ESHK(shopkeeper)->billct){
  506.         addupbill();
  507.         if(total > u.ugold){
  508.             shopkeeper->mgold += u.ugold;
  509.             u.ugold = 0;
  510.         pline("%s comes and takes all your possessions.",
  511.             Monnam(shopkeeper));
  512.         } else {
  513.             u.ugold -= total;
  514.             shopkeeper->mgold += total;
  515.     pline("%s comes and takes the %ld zorkmids you owed him.",
  516.         Monnam(shopkeeper), total);
  517.         }
  518.         setpaid();      /* in case we create bones */
  519.     }
  520. }
  521.  
  522. /* find obj on one of the lists */
  523. struct obj *
  524. bp_to_obj(bp)
  525. register struct bill_x *bp;
  526. {
  527.     register struct obj *obj;
  528.     register struct monst *mtmp;
  529.     register unsigned id = bp->bo_id;
  530.  
  531.     if(bp->useup)
  532.         obj = o_on(id, billobjs);
  533.     else if(!(obj = o_on(id, invent)) &&
  534.         !(obj = o_on(id, fobj)) &&
  535.         !(obj = o_on(id, fcobj))) {
  536.             for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
  537.             if(obj = o_on(id, mtmp->minvent))
  538.                 break;
  539.             for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon)
  540.             if(obj = o_on(id, mtmp->minvent))
  541.                 break;
  542.         }
  543.     return(obj);
  544. }
  545.  
  546. /* called in hack.c when we pickup an object */
  547. addtobill(obj) register struct obj *obj; {
  548. register struct bill_x *bp;
  549. char    buf[40];
  550. extern char *typename();
  551.     if(!inshop() ||
  552.     (u.ux == ESHK(shopkeeper)->shk.x && u.uy == ESHK(shopkeeper)->shk.y) ||
  553.     (u.ux == ESHK(shopkeeper)->shd.x && u.uy == ESHK(shopkeeper)->shd.y) ||
  554.         onbill(obj) /* perhaps we threw it away earlier */
  555.       ) return;
  556.     if(ESHK(shopkeeper)->billct == BILLSZ){
  557.         pline("You got that for free!");
  558.         return;
  559.     }
  560. #ifdef DGKMOD
  561.     /* To recognize objects the showkeeper is not interested in. -dgk
  562.      */
  563.     if (obj->no_charge) {
  564.         obj->no_charge = 0;
  565.         return;
  566.     }
  567. #endif
  568.     bp = &bill[ESHK(shopkeeper)->billct];
  569.     bp->bo_id = obj->o_id;
  570.     bp->bquan = obj->quan;
  571.     bp->useup = 0;
  572.     bp->price = getprice(obj);
  573.     strcpy(buf, "For you, ");
  574.     if (ANGRY(shopkeeper)) strcat(buf, "scum ");
  575.     else {
  576.         switch(rnd(4)
  577. #ifdef HARD
  578.            + u.udemigod
  579. #endif
  580.                 ) {
  581.         case 1: strcat(buf, "good");
  582.             break;
  583.         case 2: strcat(buf, "honored");
  584.             break;
  585.         case 3: strcat(buf, "most gracious");
  586.             break;
  587.         case 4: strcat(buf, "esteemed");
  588.             break;
  589.         case 5: strcat(buf, "holy");
  590.             break;
  591.         }
  592.         if(u.usym != '@') strcat(buf, " creature");
  593.         else          strcat(buf, (flags.female) ? " lady" : " sir");
  594.     }
  595.     pline("%s; only %d %s %s.", buf, bp->price,
  596.             (bp->bquan > 1) ? "per" : "for this",
  597.             typename((int)obj->otyp));
  598.  
  599.     ESHK(shopkeeper)->billct++;
  600.     obj->unpaid = 1;
  601. }
  602.  
  603. splitbill(obj,otmp) register struct obj *obj, *otmp; {
  604.     /* otmp has been split off from obj */
  605. register struct bill_x *bp;
  606. register int tmp;
  607.     bp = onbill(obj);
  608.     if(!bp) {
  609.         impossible("splitbill: not on bill?");
  610.         return;
  611.     }
  612.     if(bp->bquan < otmp->quan) {
  613.         impossible("Negative quantity on bill??");
  614.     }
  615.     if(bp->bquan == otmp->quan) {
  616.         impossible("Zero quantity on bill??");
  617.     }
  618.     bp->bquan -= otmp->quan;
  619.  
  620.     /* addtobill(otmp); */
  621.     if(ESHK(shopkeeper)->billct == BILLSZ) otmp->unpaid = 0;
  622.     else {
  623.         tmp = bp->price;
  624.         bp = &bill[ESHK(shopkeeper)->billct];
  625.         bp->bo_id = otmp->o_id;
  626.         bp->bquan = otmp->quan;
  627.         bp->useup = 0;
  628.         bp->price = tmp;
  629.         ESHK(shopkeeper)->billct++;
  630.     }
  631. }
  632.  
  633. subfrombill(obj) register struct obj *obj; {
  634. long ltmp;
  635. register int tmp;
  636. register struct obj *otmp;
  637. register struct bill_x *bp;
  638.     if(!inshop() || (u.ux == ESHK(shopkeeper)->shk.x && u.uy == ESHK(shopkeeper)->shk.y) ||
  639.         (u.ux == ESHK(shopkeeper)->shd.x && u.uy == ESHK(shopkeeper)->shd.y))
  640.         return;
  641.     if((bp = onbill(obj)) != 0){
  642.         obj->unpaid = 0;
  643.         if(bp->bquan > obj->quan){
  644.             otmp = newobj(0);
  645.             *otmp = *obj;
  646.             bp->bo_id = otmp->o_id = flags.ident++;
  647.             otmp->quan = (bp->bquan -= obj->quan);
  648.             otmp->owt = 0;    /* superfluous */
  649.             otmp->onamelth = 0;
  650.             bp->useup = 1;
  651.             otmp->nobj = billobjs;
  652.             billobjs = otmp;
  653.             return;
  654.         }
  655.         ESHK(shopkeeper)->billct--;
  656.         *bp = bill[ESHK(shopkeeper)->billct];
  657.         return;
  658.     }
  659.     if(obj->unpaid){
  660.         pline("%s didn't notice.", Monnam(shopkeeper));
  661.         obj->unpaid = 0;
  662.         return;     /* %% */
  663.     }
  664.     /* he dropped something of his own - probably wants to sell it */
  665.     if(shopkeeper->msleep || shopkeeper->mfroz ||
  666.         inroom(shopkeeper->mx,shopkeeper->my) != ESHK(shopkeeper)->shoproom)
  667.         return;
  668.     if(ESHK(shopkeeper)->billct == BILLSZ
  669.        || !saleable(rooms[ESHK(shopkeeper)->shoproom].rtype-SHOPBASE, obj)
  670. /*
  671.       ((tmp = shtypes[rooms[ESHK(shopkeeper)->shoproom].rtype-SHOPBASE].symb) && tmp != obj->olet)
  672. */
  673.        || index("_0", obj->olet)) {
  674.         pline("%s seems not interested.", Monnam(shopkeeper));
  675. #ifdef DGKMOD
  676.         obj->no_charge = 1;
  677. #endif
  678.         return;
  679.     }
  680.     ltmp = getprice(obj) * obj->quan;
  681.     if(ANGRY(shopkeeper)) {
  682.         ltmp /= 3;
  683.         NOTANGRY(shopkeeper) = 1;
  684.     } else    ltmp /= 2;
  685.     if(ESHK(shopkeeper)->robbed){
  686.         if((ESHK(shopkeeper)->robbed -= ltmp) < 0)
  687.             ESHK(shopkeeper)->robbed = 0;
  688. pline("Thank you for your contribution to restock this recently plundered shop.");
  689.         return;
  690.     }
  691.     if(ltmp > shopkeeper->mgold)
  692.         ltmp = shopkeeper->mgold;
  693.     pay(-ltmp, shopkeeper);
  694.     if(!ltmp) {
  695.         pline("%s gladly accepts %s but cannot pay you at present.",
  696.             Monnam(shopkeeper), doname(obj));
  697. #ifdef DGKMOD
  698.             obj->no_charge = 1;
  699. #endif
  700.     } else
  701.     pline("You sold %s and got %ld gold piece%s.", doname(obj), ltmp,
  702.         plur(ltmp));
  703. }
  704.  
  705. doinvbill(mode)
  706. int mode;        /* 0: deliver count 1: paged */
  707. {
  708.     register struct bill_x *bp;
  709.     register struct obj *obj;
  710.     long totused, thisused;
  711.     char buf[BUFSZ];
  712.  
  713.     if(mode == 0) {
  714.         register int cnt = 0;
  715.  
  716.         if(shopkeeper)
  717.         for(bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++)
  718.             if(bp->useup ||
  719.               ((obj = bp_to_obj(bp)) && obj->quan < bp->bquan))
  720.             cnt++;
  721.         return(cnt);
  722.     }
  723.  
  724.     if(!shopkeeper) {
  725.         impossible("doinvbill: no shopkeeper?");
  726.         return(0);
  727.     }
  728.  
  729.     set_pager(0);
  730.     if(page_line("Unpaid articles already used up:") || page_line(""))
  731.         goto quit;
  732.  
  733.     totused = 0;
  734.     for(bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++) {
  735.         obj = bp_to_obj(bp);
  736.         if(!obj) {
  737.         impossible("Bad shopkeeper administration.");
  738.         goto quit;
  739.         }
  740.         if(bp->useup || bp->bquan > obj->quan) {
  741.         register int cnt, oquan, uquan;
  742.  
  743.         oquan = obj->quan;
  744.         uquan = (bp->useup ? bp->bquan : bp->bquan - oquan);
  745.         thisused = bp->price * uquan;
  746.         totused += thisused;
  747.         obj->quan = uquan;        /* cheat doname */
  748.         (void) sprintf(buf, "x -  %s", doname(obj));
  749.         obj->quan = oquan;        /* restore value */
  750.         for(cnt = 0; buf[cnt]; cnt++);
  751.         while(cnt < 50)
  752.             buf[cnt++] = ' ';
  753.         (void) sprintf(&buf[cnt], " %5ld zorkmids", thisused);
  754.         if(page_line(buf))
  755.             goto quit;
  756.         }
  757.     }
  758.     (void) sprintf(buf, "Total:%50ld zorkmids", totused);
  759.     if(page_line("") || page_line(buf))
  760.         goto quit;
  761.     set_pager(1);
  762.     return(0);
  763. quit:
  764.     set_pager(2);
  765.     return(0);
  766. }
  767.  
  768. static
  769. getprice(obj) register struct obj *obj; {
  770. register int tmp, ac;
  771.     switch(obj->olet){
  772.     case AMULET_SYM:
  773.         tmp = rn1(1500, 3500);
  774.         break;
  775.     case TOOL_SYM:
  776.         switch(obj->otyp) {
  777.         case EXPENSIVE_CAMERA:    tmp = rn1(400, 200);
  778.                     break;
  779. #ifdef MARKER
  780.         case MAGIC_MARKER:    tmp = rn1(100,50);
  781.                     break;
  782. #endif
  783. #ifdef WALKIES
  784.         case LEASH:        tmp = rn1(40,20);
  785.                     break;
  786. #endif
  787. #ifdef RPH
  788.         case BLINDFOLD:     tmp = rn1(40,20);
  789.                     break;
  790.         case MIRROR:        tmp = rn1(80,40);
  791.                     break;
  792. #endif
  793.         case STETHOSCOPE:    tmp = rn1(100,80);
  794.                     break;
  795.         case CAN_OPENER:    tmp = rn1(50,30);
  796.                     break;
  797.         default:        tmp = rn1(20,10);
  798.                     break;
  799.         }
  800.         break;
  801.     case RING_SYM:
  802.         tmp = rn1(200,100);
  803.         break;
  804.     case WAND_SYM:
  805.         tmp = rn1(300,150);
  806.         break;
  807.     case SCROLL_SYM:
  808. #ifdef MAIL
  809.         if(obj->otyp == SCR_MAIL)
  810.             tmp = rn1(5,5);
  811.         else
  812. #endif
  813.             tmp = rn1(200,100);
  814.         break;
  815.     case POTION_SYM:
  816.         tmp = rn1(200,100);
  817.         break;
  818. #ifdef SPELLS
  819.     case SPBOOK_SYM:
  820.         tmp = rn1(500,500);
  821.         break;
  822. #endif
  823.     case FOOD_SYM:
  824.  
  825.         tmp = (2000+objects[obj->otyp].nutrition)/realhunger();
  826.         tmp = rn1((tmp < 10) ? 10 : tmp,
  827.               objects[obj->otyp].nutrition/20 + 5);
  828.         break;
  829.     case GEM_SYM:
  830.         tmp = rn1(120,60);
  831.         break;
  832.     case ARMOR_SYM:
  833.         ac = ARM_BONUS(obj);
  834.         if(ac <= -10)           /* probably impossible */
  835.             ac = -9;
  836.         tmp = ac*ac+10*rn1(10+ac,10);
  837.         break;
  838.     case WEAPON_SYM:
  839.         if(obj->otyp < BOOMERANG)
  840.             tmp = rn1(4,2);
  841.         else if(obj->otyp == BOOMERANG ||
  842.             obj->otyp == DAGGER ||
  843.             obj->otyp == CLUB ||
  844.             obj->otyp == SLING)
  845.             tmp = rn1(50,50);
  846.         else if(obj->otyp == KATANA)
  847.             tmp = rn1(700,800);
  848.         else if(obj->otyp == LONG_SWORD ||
  849.             obj->otyp == TWO_HANDED_SWORD ||
  850.             obj->otyp == BROAD_SWORD)
  851.             tmp = rn1(500,500);
  852.         else    tmp = rn1(150,100);
  853.         break;
  854.     case CHAIN_SYM:
  855.         pline("Strange ..., carrying a chain?");
  856.     case BALL_SYM:
  857.         tmp = 10;
  858.         break;
  859.     default:
  860.         tmp = 10000;
  861.     }
  862.     return(tmp);
  863. }
  864.  
  865. static
  866. realhunger(){   /* not completely foolproof */
  867. register tmp = u.uhunger;
  868. register struct obj *otmp = invent;
  869.     while(otmp){
  870.         if(otmp->olet == FOOD_SYM && !otmp->unpaid)
  871.             tmp += objects[otmp->otyp].nutrition;
  872.         otmp = otmp->nobj;
  873.     }
  874.     return((tmp <= 0) ? 1 : tmp);
  875. }
  876.  
  877. shkcatch(obj)
  878. register struct obj *obj;
  879. {
  880.     register struct monst *shkp = shopkeeper;
  881.  
  882.     if(u.uinshop && shkp && !shkp->mfroz && !shkp->msleep &&
  883.         u.dx && u.dy &&
  884.         inroom(u.ux+u.dx, u.uy+u.dy) + 1 == u.uinshop &&
  885.         shkp->mx == ESHK(shkp)->shk.x && shkp->my == ESHK(shkp)->shk.y &&
  886.         u.ux == ESHK(shkp)->shd.x && u.uy == ESHK(shkp)->shd.y) {
  887.         pline("%s nimbly catches the %s.", Monnam(shkp), xname(obj));
  888.         obj->nobj = shkp->minvent;
  889.         shkp->minvent = obj;
  890.         return(1);
  891.     }
  892.     return(0);
  893. }
  894.  
  895. /*
  896.  * shk_move: return 1: he moved  0: he didnt  -1: let m_move do it
  897.  */
  898. shk_move(shkp)
  899. register struct monst *shkp;
  900. {
  901.     register struct monst *mtmp;
  902.     register struct permonst *mdat = shkp->data;
  903.     register xchar gx,gy,omx,omy,nx,ny,nix,niy;
  904.     register schar appr,i;
  905.     register int udist;
  906.     int z;
  907.     schar shkroom,chi,chcnt,cnt;
  908.     boolean uondoor, satdoor, avoid, badinv;
  909.     coord poss[9];
  910.     long info[9];
  911.     struct obj *ib = 0;
  912.  
  913.     omx = shkp->mx;
  914.     omy = shkp->my;
  915.  
  916.     if((udist = dist(omx,omy)) < 3) {
  917.         if(ANGRY(shkp)) {
  918.             (void) hitu(shkp, d(mdat->damn, mdat->damd)+1);
  919.             return(0);
  920.         }
  921.         if(ESHK(shkp)->following) {
  922.             if(strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)){
  923.             pline("Hello %s%s! I was looking for %s.",
  924.                 (Badged) ? "Officer " : "",
  925.                 plname, ESHK(shkp)->customer);
  926.                 ESHK(shkp)->following = 0;
  927.                 return(0);
  928.             }
  929.             if(!ESHK(shkp)->robbed) {       /* impossible? */
  930.                 ESHK(shkp)->following = 0;
  931.                 return(0);
  932.             }
  933.             if(moves > followmsg+4) {
  934.                 pline("Hello %s%s! Didn't you forget to pay?",
  935.                     (Badged) ? "Officer " : "", plname);
  936.                 followmsg = moves;
  937.                 if (Badged)
  938.                     pline ("You should be upholding the law!");
  939. #ifdef HARD
  940.                 if (!rn2((Badged) ? 3 : 5)) {
  941.         pline ("%s doesn't like customers who don't pay.", Monnam(shkp));
  942.                     NOTANGRY(shkp) = 0;
  943.                 }
  944. #endif
  945.             }
  946.             if(udist < 2)
  947.                 return(0);
  948.         }
  949.     }
  950.  
  951.     shkroom = inroom(omx,omy);
  952.     appr = 1;
  953.     gx = ESHK(shkp)->shk.x;
  954.     gy = ESHK(shkp)->shk.y;
  955.     satdoor = (gx == omx && gy == omy);
  956.     if(ESHK(shkp)->following || ((z = holetime()) >= 0 && z*z <= udist)){
  957.         gx = u.ux;
  958.         gy = u.uy;
  959.         if(shkroom < 0 || shkroom != inroom(u.ux,u.uy))
  960.             if(udist > 4)
  961.             return(-1);     /* leave it to m_move */
  962.     } else if(ANGRY(shkp)) {
  963.         long saveBlind = Blinded;
  964.         long saveBlindf = Blindfolded;
  965.         Blinded = Blindfolded = 0;
  966.         if(shkp->mcansee && !Invis && cansee(omx,omy)) {
  967.             gx = u.ux;
  968.             gy = u.uy;
  969.         }
  970.         Blinded = saveBlind;
  971.         Blindfolded = saveBlindf;
  972.         avoid = FALSE;
  973.     } else {
  974. #define GDIST(x,y)      ((x-gx)*(x-gx)+(y-gy)*(y-gy))
  975.         if(Invis)
  976.           avoid = FALSE;
  977.         else {
  978.           uondoor = (u.ux == ESHK(shkp)->shd.x &&
  979.                 u.uy == ESHK(shkp)->shd.y);
  980.           if(uondoor) {
  981.             if(ESHK(shkp)->billct)
  982.             pline("Hello %s%s! Will you please pay before leaving?",
  983.                 (Badged) ? "Officer " : "", plname);
  984.             badinv = (carrying(PICK_AXE) || carrying(ICE_BOX));
  985.             if(satdoor && badinv)
  986.             return(0);
  987.             avoid = !badinv;
  988.           } else {
  989.             avoid = (u.uinshop && dist(gx,gy) > 8);
  990.             badinv = FALSE;
  991.           }
  992.  
  993.           if(((!ESHK(shkp)->robbed && !ESHK(shkp)->billct) || avoid)
  994.             && GDIST(omx,omy) < 3){
  995.             if(!badinv && !online(omx,omy))
  996.                 return(0);
  997.             if(satdoor)
  998.                 appr = gx = gy = 0;
  999.           }
  1000.         }
  1001.     }
  1002.     if(omx == gx && omy == gy)
  1003.         return(0);
  1004.     if(shkp->mconf) {
  1005.         avoid = FALSE;
  1006.         appr = 0;
  1007.     }
  1008.     nix = omx;
  1009.     niy = omy;
  1010.     cnt = mfndpos(shkp,poss,info,ALLOW_SSM);
  1011.     if(avoid && uondoor) {          /* perhaps we cannot avoid him */
  1012.         for(i=0; i<cnt; i++)
  1013.             if(!(info[i] & NOTONL)) goto notonl_ok;
  1014.         avoid = FALSE;
  1015.     notonl_ok:
  1016.         ;
  1017.     }
  1018.     chi = -1;
  1019.     chcnt = 0;
  1020.     for(i=0; i<cnt; i++){
  1021.         nx = poss[i].x;
  1022.         ny = poss[i].y;
  1023.         if (RM_TYP(levl[nx][ny]) == ROOM
  1024.         || shkroom != ESHK(shkp)->shoproom
  1025.         || ESHK(shkp)->following) {
  1026. #ifdef STUPID
  1027.             /* cater for stupid compilers */
  1028.             register int zz;
  1029. #endif
  1030.             if(uondoor && (ib = sobj_at(ICE_BOX, nx, ny))) {
  1031.             nix = nx; niy = ny; chi = i; break;
  1032.             }
  1033.             if(avoid && (info[i] & NOTONL))
  1034.             continue;
  1035.             if((!appr && !rn2(++chcnt)) ||
  1036. #ifdef STUPID
  1037.             (appr && (zz = GDIST(nix,niy)) && zz > GDIST(nx,ny))
  1038. #else
  1039.             (appr && GDIST(nx,ny) < GDIST(nix,niy))
  1040. #endif
  1041.             ) {
  1042.                 nix = nx;
  1043.                 niy = ny;
  1044.                 chi = i;
  1045.             }
  1046.         }
  1047.     }
  1048.     if(nix != omx || niy != omy){
  1049.         if(info[chi] & ALLOW_M){
  1050.             mtmp = m_at(nix,niy);
  1051.             if(hitmm(shkp,mtmp) == 1 && rn2(3) &&
  1052.                hitmm(mtmp,shkp) == 2) return(2);
  1053.             return(0);
  1054.         } else if(info[chi] & ALLOW_U){
  1055.             (void) hitu(shkp, d(mdat->damn, mdat->damd)+1);
  1056.             return(0);
  1057.         }
  1058.         shkp->mx = nix;
  1059.         shkp->my = niy;
  1060.         pmon(shkp);
  1061.         if(ib) {
  1062.             freeobj(ib);
  1063.             mpickobj(shkp, ib);
  1064.         }
  1065.         return(1);
  1066.     }
  1067.     return(0);
  1068. }
  1069. #endif /* QUEST /**/
  1070.  
  1071. online(x,y)             /*      New version to speed things up.
  1072.              *    Compiler dependant, may not always work.
  1073.              */
  1074.     register xchar x, y;
  1075. {
  1076.     return((x-=u.ux) == 0 || (y-=u.uy) == 0 || x == y || (x+=y) == 0);
  1077. }
  1078.  
  1079. /*            Original version, just in case...
  1080.  *online(x,y) {
  1081.  *    return(x==u.ux || y==u.uy || (x-u.ux)*(x-u.ux) == (y-u.uy)*(y-u.uy));
  1082.  *}
  1083.  */
  1084.  
  1085. /* Does this monster follow me downstairs? */
  1086. follower(mtmp)
  1087. register struct monst *mtmp;
  1088. {
  1089.     return( mtmp->mtame || index("1TVWZi&, ", mtmp->data->mlet) ||
  1090.         (mtmp->isshk && ESHK(mtmp)->following) );
  1091. }
  1092.  
  1093. /* He is digging in the shop. */
  1094. shopdig(fall)
  1095. register int fall;
  1096. {
  1097.     if(!fall) {
  1098.     if(u.utraptype == TT_PIT)
  1099.         pline("\"Be careful, sir, or you might fall through the floor.\"");
  1100.     else
  1101.         pline("\"Please, do not damage the floor here.\"");
  1102.     } else if(dist(shopkeeper->mx, shopkeeper->my) < 3) {
  1103.     register struct obj *obj, *obj2;
  1104.  
  1105.     pline("%s grabs your backpack!", shkname(shopkeeper));
  1106.     for(obj = invent; obj; obj = obj2) {
  1107.         obj2 = obj->nobj;
  1108.         if(obj->owornmask) continue;
  1109.         freeinv(obj);
  1110.         obj->nobj = shopkeeper->minvent;
  1111.         shopkeeper->minvent = obj;
  1112.         if(obj->unpaid)
  1113.             subfrombill(obj);
  1114.     }
  1115.     }
  1116. }
  1117.